package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"path"

	//	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/gin-gonic/gin"
)

var (
	conf   *Config
	videos []string
)

func searchGET(c *gin.Context) {
	c.Request.ParseForm()
	k := c.Param("k")
	req, _ := http.NewRequest("GET", "http://ios.zmzapi.com/index.php", nil)
	q := req.URL.Query()
	q.Add("g", "api/pv3")
	q.Add("m", "index")
	q.Add("client", "5")
	q.Add("accesskey", "519f9cab85c8059d17544947k361a827")
	q.Add("a", "search")
	q.Add("uid", "")
	q.Add("token", "")
	q.Add("page", "1")
	q.Add("limit", "30")
	q.Add("k", k)
	req.URL.RawQuery = q.Encode()
	resp, e := http.DefaultClient.Do(req)
	if e == nil {
		defer resp.Body.Close()
		if resp.StatusCode == 200 {
			body, _ := ioutil.ReadAll(resp.Body)
			c.String(200, string(body))
		}
		return
	}
	c.JSON(400, gin.H{"ret": -1, "msg": "Fail to request"})
}

func resourceGET(c *gin.Context) {
	c.Request.ParseForm()
	id := c.Param("id")
	req, _ := http.NewRequest("GET", "http://ios.zmzapi.com/index.php", nil)
	q := req.URL.Query()
	q.Add("g", "api/pv3")
	q.Add("m", "index")
	q.Add("client", "5")
	q.Add("accesskey", "519f9cab85c8059d17544947k361a827")
	q.Add("a", "resource")
	q.Add("uid", "undefined")
	q.Add("token", "undefined")
	q.Add("id", id)
	req.URL.RawQuery = q.Encode()
	// log.Println(req.URL)
	resp, e := http.DefaultClient.Do(req)
	if e == nil {
		defer resp.Body.Close()
		if resp.StatusCode == 200 {
			body, _ := ioutil.ReadAll(resp.Body)
			c.String(200, string(body))
		}
		return
	}
	c.JSON(400, gin.H{"ret": -1, "msg": "Fail to request"})
}

func addPOST(c *gin.Context) {
	c.Request.ParseForm()
	addr := c.Param("addr")
	port := c.Param("port")
	body, _ := ioutil.ReadAll(c.Request.Body)
	jd := map[string]string{}
	json.Unmarshal(body, &jd)
	uri := jd["uri"]
	jstr := make(map[string]interface{})
	jstr["jsonrpc"] = "2.0"
	jstr["id"] = "q"
	jstr["method"] = "aria2.addUri"
	jstr["params"] = [][]string{[]string{uri}}
	bytesData, _ := json.Marshal(jstr)
	reader := bytes.NewReader(bytesData)
	req, _ := http.NewRequest("POST", "http://"+addr+":"+port+"/jsonrpc", reader)
	req.Header.Set("Content-Type", "application/json;charset=UTF-8")
	resp, e := http.DefaultClient.Do(req)
	if e == nil {
		defer resp.Body.Close()
		if resp.StatusCode == 200 {
			body, _ := ioutil.ReadAll(resp.Body)
			c.String(200, string(body))
		}
		return
	}
	c.JSON(400, gin.H{"ret": -1, "msg": "Fail to request"})
}

func videosGET(c *gin.Context) {
	c.JSON(200, gin.H{"videos": videos})
}

func getFiles(files *[]string, dirPath string, filterFunc func(string) bool) error {
	rd, e := ioutil.ReadDir(dirPath)
	if e != nil {
		return e
	}
	for _, fi := range rd {
		fileName := fi.Name()
		filePath := dirPath + fileName
		if fi.IsDir() {
			e = getFiles(files, filePath+"/", filterFunc)
			if e != nil {
				return e
			}
		} else if filterFunc(fileName) {
			*files = append(*files, filePath)
		}
	}
	return nil
}

func checkVideo(name string) bool {
	ext := path.Ext(name)
	if ext == ".mp4" || ext == ".mkv" {
		return true
	}
	return false
}

func scanVideos(dirPath string) {
	videos = []string{}
	if e := getFiles(&videos, dirPath, checkVideo); e != nil {
		log.Fatalln(e.Error())
	}
}

func main() {
	var err error
	conf, err = loadConf("./conf.json")
	if err != nil {
		panic(err)
	}

	if conf.Mode == "dev" {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	scanVideos(conf.FilePath)

	router := gin.New()
	router.Static("/home", conf.StaticPath)
	router.StaticFS("/mv", gin.Dir(conf.FilePath, true))
	router.GET("/search/:k", searchGET)
	router.GET("/resource/:id", resourceGET)
	router.POST("/add/:addr/:port", addPOST)
	router.GET("/videos", videosGET)

	srv := &http.Server{
		Addr:         fmt.Sprintf("%s:%d", conf.Ip, conf.Port),
		Handler:      router,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
		//		MaxHeaderBytes: 1 << 20,
	}

	go func() {
		err := srv.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			panic(err)
		}
	}()
	log.Printf("server on: http://%s:%d/\n", conf.Ip, conf.Port)

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	log.Println("server shutdown")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err = srv.Shutdown(ctx); err != nil {
		log.Fatal("server shutdown, error:", err)
	}
	log.Println("server exit")
}
